package com.kurt.service.impl;

import com.kurt.dto.MenuDTO;
import com.kurt.dto.RoleDTO;
import com.kurt.dto.create.RoleCreateRequest;
import com.kurt.dto.query.RoleQueryRequest;
import com.kurt.dto.update.RoleUpdateRequest;
import com.kurt.entity.SysMenu;
import com.kurt.entity.SysRole;
import com.kurt.entity.SysRoleMenu;
import com.kurt.entity.SysUserRole;
import com.kurt.repository.SysMenuRepository;
import com.kurt.repository.SysRoleMenuRepository;
import com.kurt.repository.SysRoleRepository;
import com.kurt.repository.SysUserRoleRepository;
import com.kurt.service.RoleService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 角色服务实现类
 * 实现角色相关的业务逻辑
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class RoleServiceImpl extends BaseServiceImpl<SysRole, Long> implements RoleService {

    private final SysRoleRepository roleRepository;
    private final SysRoleMenuRepository roleMenuRepository;
    private final SysMenuRepository menuRepository;
    private final SysUserRoleRepository userRoleRepository;

    @Override
    protected SysRoleRepository getRepository() {
        return roleRepository;
    }

    @Override
    protected SysRoleRepository getSpecificationExecutor() {
        return roleRepository;
    }

    @Override
    @Transactional
    public RoleDTO createRole(RoleCreateRequest createRequest) {
        log.info("创建角色: {}", createRequest.getName());

        // 检查角色名称是否已存在
        if (roleRepository.findByName(createRequest.getName()).isPresent()) {
            throw new RuntimeException("角色名称已存在");
        }

        // 检查角色编码是否已存在
        if (roleRepository.findByCode(createRequest.getCode()).isPresent()) {
            throw new RuntimeException("角色编码已存在");
        }

        // 创建角色实体
        SysRole role = new SysRole();
        BeanUtils.copyProperties(createRequest, role);
        role.setCreateTime(LocalDateTime.now());
        role.setUpdateTime(LocalDateTime.now());

        // 保存角色
        role = roleRepository.save(role);

        // 分配菜单权限
        if (createRequest.getMenuIds() != null && !createRequest.getMenuIds().isEmpty()) {
            assignMenus(role.getId(), createRequest.getMenuIds());
        }

        log.info("角色创建成功: {}", role.getName());
        return convertToRoleDTO(role);
    }

    @Override
    @Transactional
    public RoleDTO updateRole(RoleUpdateRequest updateRequest) {
        log.info("更新角色: {}", updateRequest.getId());

        // 查找角色
        SysRole role = getById(updateRequest.getId());

        // 检查角色名称是否已存在（排除自己）
        if (StringUtils.hasText(updateRequest.getName()) &&
                !updateRequest.getName().equals(role.getName()) &&
                roleRepository.findByName(updateRequest.getName()).isPresent()) {
            throw new RuntimeException("角色名称已存在");
        }

        // 检查角色编码是否已存在（排除自己）
        if (StringUtils.hasText(updateRequest.getCode()) &&
                !updateRequest.getCode().equals(role.getCode()) &&
                roleRepository.findByCode(updateRequest.getCode()).isPresent()) {
            throw new RuntimeException("角色编码已存在");
        }

        // 更新角色信息
        if (StringUtils.hasText(updateRequest.getName())) {
            role.setName(updateRequest.getName());
        }
        if (StringUtils.hasText(updateRequest.getCode())) {
            role.setCode(updateRequest.getCode());
        }
        if (StringUtils.hasText(updateRequest.getDescription())) {
            role.setDescription(updateRequest.getDescription());
        }
        if (updateRequest.getStatus() != null) {
            role.setStatus(updateRequest.getStatus());
        }
        if (updateRequest.getSortOrder() != null) {
            role.setSortOrder(updateRequest.getSortOrder());
        }
        if (StringUtils.hasText(updateRequest.getRemark())) {
            role.setRemark(updateRequest.getRemark());
        }
        role.setUpdateTime(LocalDateTime.now());

        // 保存角色
        role = roleRepository.save(role);

        // 更新菜单权限
        if (updateRequest.getMenuIds() != null) {
            assignMenus(role.getId(), updateRequest.getMenuIds());
        }

        log.info("角色更新成功: {}", role.getName());
        return convertToRoleDTO(role);
    }

    @Override
    public RoleDTO getRoleById(Long id) {
        SysRole role = getById(id);
        return convertToRoleDTO(role);
    }

    @Override
    public Page<RoleDTO> getRolePage(RoleQueryRequest queryRequest) {
        // 构建分页参数
        Sort sort = Sort.by(Sort.Direction.fromString(queryRequest.getOrderDirection()), queryRequest.getOrderBy());
        Pageable pageable = PageRequest.of(queryRequest.getPageNum() - 1, queryRequest.getPageSize(), sort);

        // 构建查询条件
        Specification<SysRole> spec = buildRoleSpecification(queryRequest);

        // 执行分页查询
        Page<SysRole> rolePage = roleRepository.findAll(spec, pageable);

        // 转换为DTO
        return rolePage.map(this::convertToRoleDTO);
    }

    @Override
    public List<RoleDTO> getRoleList(RoleQueryRequest queryRequest) {
        // 构建查询条件
        Specification<SysRole> spec = buildRoleSpecification(queryRequest);

        // 执行查询
        List<SysRole> roles = roleRepository.findAll(spec);

        // 转换为DTO
        return roles.stream().map(this::convertToRoleDTO).collect(Collectors.toList());
    }

    @Override
    @Transactional
    public boolean deleteRole(Long id) {
        log.info("删除角色: {}", id);

        // 检查是否有用户使用该角色
        List<SysUserRole> userRoles = userRoleRepository.findByRoleId(id);
        if (!userRoles.isEmpty()) {
            throw new RuntimeException("该角色下还有用户，无法删除");
        }

        // 删除角色菜单关联
        roleMenuRepository.deleteByRoleId(id);

        // 删除角色
        roleRepository.deleteById(id);

        log.info("角色删除成功: {}", id);
        return true;
    }

    @Override
    @Transactional
    public boolean deleteRoles(List<Long> ids) {
        log.info("批量删除角色: {}", ids);

        for (Long id : ids) {
            deleteRole(id);
        }

        log.info("批量删除角色成功: {}", ids);
        return true;
    }

    @Override
    @Transactional
    public boolean assignMenus(Long roleId, List<Long> menuIds) {
        log.info("分配角色菜单权限: roleId={}, menuIds={}", roleId, menuIds);

        // 删除原有菜单权限
        roleMenuRepository.deleteByRoleId(roleId);

        // 添加新的菜单权限
        if (menuIds != null && !menuIds.isEmpty()) {
            List<SysRoleMenu> roleMenus = new ArrayList<>();
            for (Long menuId : menuIds) {
                SysRoleMenu roleMenu = new SysRoleMenu();
                roleMenu.setRoleId(roleId);
                roleMenu.setMenuId(menuId);
                roleMenu.setCreateTime(LocalDateTime.now());
                roleMenu.setUpdateTime(LocalDateTime.now());
                roleMenus.add(roleMenu);
            }
            roleMenuRepository.saveAll(roleMenus);
        }

        log.info("角色菜单权限分配成功: roleId={}", roleId);
        return true;
    }

    @Override
    public List<MenuDTO> getRoleMenus(Long roleId) {
        List<SysMenu> menus = menuRepository.findByRoleId(roleId);
        return menus.stream().map(this::convertToMenuDTO).collect(Collectors.toList());
    }

    @Override
    public boolean existsByName(String name) {
        return roleRepository.findByName(name).isPresent();
    }

    @Override
    public boolean existsByNameAndIdNot(String name, Long excludeId) {
        return roleRepository.findByNameAndIdNot(name, excludeId).isPresent();
    }

    @Override
    public boolean existsByCode(String code) {
        return roleRepository.findByCode(code).isPresent();
    }

    @Override
    public boolean existsByCodeAndIdNot(String code, Long excludeId) {
        return roleRepository.findByCodeAndIdNot(code, excludeId).isPresent();
    }

    @Override
    @Transactional
    public boolean updateStatus(Long id, Integer status) {
        log.info("更新角色状态: id={}, status={}", id, status);

        SysRole role = getById(id);
        role.setStatus(status);
        role.setUpdateTime(LocalDateTime.now());
        roleRepository.save(role);

        log.info("角色状态更新成功: id={}, status={}", id, status);
        return true;
    }

    @Override
    @Transactional
    public boolean updateSortOrder(Long id, Integer sortOrder) {
        log.info("更新角色排序: id={}, sortOrder={}", id, sortOrder);

        SysRole role = getById(id);
        role.setSortOrder(sortOrder);
        role.setUpdateTime(LocalDateTime.now());
        roleRepository.save(role);

        log.info("角色排序更新成功: id={}, sortOrder={}", id, sortOrder);
        return true;
    }

    /**
     * 构建角色查询条件
     *
     * @param queryRequest 查询请求
     * @return 查询条件
     */
    private Specification<SysRole> buildRoleSpecification(RoleQueryRequest queryRequest) {
        return (root, query, cb) -> {
            List<jakarta.persistence.criteria.Predicate> predicates = new ArrayList<>();

            // 角色名称模糊查询
            if (StringUtils.hasText(queryRequest.getName())) {
                predicates.add(cb.like(root.get("name"), "%" + queryRequest.getName() + "%"));
            }

            // 角色编码模糊查询
            if (StringUtils.hasText(queryRequest.getCode())) {
                predicates.add(cb.like(root.get("code"), "%" + queryRequest.getCode() + "%"));
            }

            // 状态查询
            if (queryRequest.getStatus() != null) {
                predicates.add(cb.equal(root.get("status"), queryRequest.getStatus()));
            }

            // 创建时间范围查询
            if (StringUtils.hasText(queryRequest.getCreateTimeStart())) {
                predicates.add(cb.greaterThanOrEqualTo(root.get("createTime"),
                        LocalDateTime.parse(queryRequest.getCreateTimeStart())));
            }
            if (StringUtils.hasText(queryRequest.getCreateTimeEnd())) {
                predicates.add(cb.lessThanOrEqualTo(root.get("createTime"),
                        LocalDateTime.parse(queryRequest.getCreateTimeEnd())));
            }

            return cb.and(predicates.toArray(new jakarta.persistence.criteria.Predicate[0]));
        };
    }

    /**
     * 转换角色实体为DTO
     *
     * @param role 角色实体
     * @return 角色DTO
     */
    private RoleDTO convertToRoleDTO(SysRole role) {
        RoleDTO roleDTO = new RoleDTO();
        BeanUtils.copyProperties(role, roleDTO);

        // 获取角色菜单权限
        List<SysMenu> menus = menuRepository.findByRoleId(role.getId());
        roleDTO.setMenus(menus.stream().map(this::convertToMenuDTO).collect(Collectors.toList()));
        roleDTO.setMenuIds(menus.stream().map(SysMenu::getId).collect(Collectors.toList()));

        // 获取用户数量
        List<SysUserRole> userRoles = userRoleRepository.findByRoleId(role.getId());
        roleDTO.setUserCount((long) userRoles.size());

        return roleDTO;
    }

    /**
     * 转换菜单实体为DTO
     *
     * @param menu 菜单实体
     * @return 菜单DTO
     */
    private MenuDTO convertToMenuDTO(SysMenu menu) {
        MenuDTO menuDTO = new MenuDTO();
        BeanUtils.copyProperties(menu, menuDTO);
        return menuDTO;
    }
}
